package cn.itsource.service.impl;

import cn.dev33.satoken.stp.SaLoginConfig;
import cn.dev33.satoken.stp.StpUtil;

import cn.itsource.constants.CacheConstants;
import cn.itsource.constants.ErrorCode;
import cn.itsource.constants.RConst;
import cn.itsource.pojo.domain.Login;
import cn.itsource.mapper.LoginMapper;
import cn.itsource.pojo.dto.RegisterDto;
import cn.itsource.pojo.ro.AppLoginRo;
import cn.itsource.pojo.ro.ManagerPassword;
import cn.itsource.pojo.vo.ManagerInfoVo;
import cn.itsource.pojo.vo.UserInfoVo;
import cn.itsource.result.JSONResult;
import cn.itsource.service.ILoginService;
import cn.itsource.service.WechatService;
import cn.itsource.utils.AssertUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 登录表 服务实现类
 * </p>
 *
 * @author whale
 * @since 2024-07-07
 */
@Service
@Slf4j
public class LoginServiceImpl extends ServiceImpl<LoginMapper, Login> implements ILoginService {

        @Autowired
        private WechatService wechatService;
        @Autowired
        private LoginMapper loginMapper;
        @Autowired
        private RedisTemplate redisTemplate;
        @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;
    @Override
    public JSONResult appLogin(AppLoginRo login) {
        RegisterDto wechatOpenId = wechatService.getWechatOpenId(login.getCode());
        String openid = wechatOpenId.getOpenid();
        //assertUtil是一个工具类 这个工具类的作用是来判断openid是否为空 如果为空就报错
        AssertUtil.isNotNull(openid,"获取openid失败了");
        //打印错误信息日志
        log.info("当前code:{}获取openId失败",login.getCode());
        //既是用户又是司机
        Login one = super.getOne(new LambdaQueryWrapper<Login>().eq(Login::getOpenId, openid)
                .eq(Login::getType, login.getType()));
         if( one != null){
             //jwt的方式 相当于把one放入userinfo 这是后端取值的方法 类似于刚刚返回前端对象的时候用对象取值
             //这路的代码是将用户数据保存到token里面
             StpUtil.login(one.getId(), SaLoginConfig.setExtra("userinfo",one));
            //登录成功就需要查询数据库 将权限保存到redis里面
            getPermissionList(one);
             String tokenValue = StpUtil.getTokenValue();
             UserInfoVo userInfoVo = UserInfoVo.toUserInfoVo(one,tokenValue);
             return JSONResult.success(userInfoVo);
         }else {
             return JSONResult.error(ErrorCode.WE_CHAT_LOGIN_ERROR);
         }
    }

    @Override
    public JSONResult managerLogin(Login login) {
        //先确定有没有用户
        String username = login.getUsername();
        Integer type = login.getType();
        Login one = super.getOne(new LambdaQueryWrapper<Login>()
                .eq(Login::getUsername, username).eq(Login::getType, type));
        AssertUtil.isNotNull(one,"用户密码或者账号错误");
        //确定密码对不对
       boolean matches = bCryptPasswordEncoder.matches(login.getPassword(), one.getPassword());
        AssertUtil.isTrue(matches,"用户密码或者账号错误");
        //判断当前账号是否能用
        AssertUtil.isTrue(one.getEnabled(),"此账号无法使用");
        //登录成功就需要查询数据库 将权限保存到redis里面
        List<String> permissionList = getPermissionList(one);
        //得到token值
        String tokenValue = StpUtil.getTokenValue();
        //由于需要返回对象 但是密码绝对不能显示 所以需要先设置密码值
        one.setPassword("");
        //封装对象 然后token 和权限还有对象one传入 一起全部封装给前端
        ManagerInfoVo managerInfoVo = new ManagerInfoVo(tokenValue,permissionList,one);
        return  JSONResult.success(managerInfoVo);

    }

    @Override
    public JSONResult managerOut() {
        StpUtil.logout();
        return JSONResult.success();
    }

    @Override
    public JSONResult updatePassword(ManagerPassword pwd) {
        String login = pwd.getLogin();
        Login login1 = JSONObject.parseObject(login, Login.class);
        String newPassWord = pwd.getNewPassword();
        String oldPassword = pwd.getOldPassword();
        if (!newPassWord.equals(oldPassword)){
            if (bCryptPasswordEncoder.matches(oldPassword,loginMapper.selectById(login1.getId()).getPassword())){
                Login log = login1;
                log.setPassword(bCryptPasswordEncoder.encode(newPassWord));
                 loginMapper.updateById(log);
                System.out.println(log.getPassword());
                return JSONResult.message("修改成功");
            }
        }
        return JSONResult.error("修改失败");
    }

    @Override
    public JSONResult pictureOnload(String path) {
        File file = new File(path);
        int endwith = path.lastIndexOf(".");
        String substring = path.substring(endwith + 1);
        String s = new String("." + substring);

        return null;
    }

    public static void main(String[] args) {
        String path = "/path/to/image.jpg"; // 图片文件路径
        int lastDotIndex = path.lastIndexOf(".");
        String imageExtension = path.substring(lastDotIndex + 1);
        System.out.println("Image extension: " + "."+imageExtension);
    }


    private List<String> getPermissionList(Login one) {
        //登录成功 这里的代码就将用户数据保存到token里面 jwt
        StpUtil.login(one.getId(),
                SaLoginConfig.setExtra("userinfo", one).setExtra("openId",one.getOpenId()));
        //存入redis
        String key = CacheConstants.CURRENT_LOGIN_PERMISSION+ one.getId().toString();

        //去查询数据库 将权限保存到redis里面
        List<String> permissionList =
                loginMapper.selectPermissionByLoginId(Long.valueOf(one.getId().toString()));
        System.err.println(String.join(",",permissionList));
        redisTemplate.opsForValue().set(key,permissionList, RConst.Num.INT_30, TimeUnit.MINUTES);
        return permissionList;
    }
}
